package com.xiyan.mq.config;

import com.xiyan.mq.receiver.Tut2Receiver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author: ruiyanglee
 * @date: 2020-11-09 14:08
 * @description:
 */

//@Profile({"tut1","hello-world"})
@Configuration
public class RabbitMqConfig {

    private static final Logger log = LoggerFactory.getLogger(RabbitMqConfig.class);

    @Value("${spring.rabbitmq.host}")
    private String addresses;
    @Value("${spring.rabbitmq.port}")
    private Integer port;
    @Value("${spring.rabbitmq.username}")
    private String username;
    @Value("${spring.rabbitmq.password}")
    private String password;

    @Value(value = "${spring.rabbitmq.virtual-host}")
    private String virtualHost;


    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(this.addresses);
        connectionFactory.setPort(this.port);
        connectionFactory.setUsername(this.username);
        connectionFactory.setPassword(this.password);
        connectionFactory.setVirtualHost(this.virtualHost);
        connectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.SIMPLE);
        connectionFactory.setPublisherReturns(true);
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }

    @Bean
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(this.connectionFactory());
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());

        // 消息只要被rabbit broker接收到就会执行confirmCallback
        // 被broker执行只能保证消息到达服务器，并不能保证一定被投递到目标queue里
        rabbitTemplate.setConfirmCallback((data, ack, cause) ->{
//            String msgId = data.getId();
            if (ack) {
                log.info("消息发送成功!!!");
            }else{
                log.info("消息发送失败!!!");
            }
        });
        // 触发setReturnCallback回调必须设置mandatory=true, 否则Exchange没有找到Queue就会丢弃掉消息, 而不会触发回调
        rabbitTemplate.setMandatory(true);

        // 消息是否从Exchange路由到Queue, 注意: 这是一个失败回调, 只有消息从Exchange路由到Queue失败才会回调这个方法
        rabbitTemplate.setReturnsCallback((returnedMessage) -> {
            log.info("消息从Exchange路由到Queue失败: exchange: {}, route: {}, replyCode: {}, replyText: {}, message: {}", returnedMessage.getExchange(),
                    returnedMessage.getRoutingKey(), returnedMessage.getReplyCode(),
                    returnedMessage.getReplyText(), returnedMessage.getMessage());
        });
        return rabbitTemplate;
    }

    // 2 receiver beans
    @Bean
    public Tut2Receiver receiver1() {
        return new Tut2Receiver();
    }

//    @Bean
//    public Tut2Receiver receiver2() {
//        return new Tut2Receiver();
//    }

    // define exchange bean with tut.fanout name
    @Bean
    public DirectExchange direct() {
        return new DirectExchange ("tut.direct");
    }

    // 2 AnonymousQueues (non-durable, exclusive, auto-delete queues in AMQP terms)
    @Bean
    public Queue autoDeleteQueue1() {
        return QueueBuilder.durable("MQ-KEY").build();
    }

    @Bean
    public Queue autoDeleteQueue2() {
        return QueueBuilder.durable("MQ-LOG").build();
    }


    // 2 bindings to bind those queues to the exchange.
    @Bean
    public Binding bindingDirectExchange(DirectExchange direct,
                             Queue autoDeleteQueue1) {
        return BindingBuilder.bind(autoDeleteQueue1)
                .to(direct)
                .with("error");
    }


    @Bean
    public Binding binding2a(DirectExchange direct,
                             Queue autoDeleteQueue2) {
        return BindingBuilder.bind(autoDeleteQueue2)
                .to(direct)
                .with("info");
    }

    @Bean
    public Binding binding2b(DirectExchange direct,
                             Queue autoDeleteQueue2) {
        return BindingBuilder.bind(autoDeleteQueue2)
                .to(direct)
                .with("warning");
    }
}
